package myfamily.model;

import java.util.*;

import javax.jdo.Query;

public class GenericPerson
{
	private String treeID;
	private int generationID;
	private Name PersonName;
	private String gender;
	private String religion;
	private String ethnicity;
	private Date dateOfBirth;
	private Date dateOfPassing;
	private Contact contactDetails;
	private ArrayList<String> languages;
	private ArrayList<Marriage> maritalList;
	private ArrayList<Address> resAddresses;
	private ArrayList<Education> education;
	private ArrayList<Occupation> work;
	private Marriage childOf;
	private RegisteredUser addedBy;


	/**
	 * 
	 */
	protected GenericPerson() {
		languages = new ArrayList<String>();
		maritalList = new ArrayList<Marriage>();
		resAddresses = new ArrayList<Address>();
		education = new ArrayList<Education>();
		work = new ArrayList<Occupation>();

		languages.clear();
		maritalList.clear();
		resAddresses.clear();
		education.clear();
		work.clear();
		generationID = 0;
	}


	public void persist()
	{
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		db.pm.makePersistent(this);
		db.pm.currentTransaction().commit();
	}

	private void changeTree(String newTreeID)
	{
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		Query q = db.pm.newQuery(GenericPerson.class);

		q.setFilter("treeID == \"" + this.treeID + "\""); 

		Collection ans = null;
		try{
			ans = (Collection)q.execute();

			for(Iterator i = ans.iterator(); i.hasNext() ; )
			{
				GenericPerson gp = (GenericPerson)i.next();
				gp.setTreeID(newTreeID);
			}
		}

		catch(Exception e)
		{
			e.printStackTrace();
			System.exit(0);
		}
	}

	public static GenericPerson searchByEmail(String searchEmail)
	{
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		Query q = db.pm.newQuery(RegisteredUser.class);
		System.out.println(searchEmail);
		q.setFilter("contactDetails.email == \""+ searchEmail +"\""); 
		//q.setFilter("contactDetails.email == \"jatin.hello@gmail.com\""); 
		Collection ans = null;
		try{
			ans = (Collection)q.execute();

			if(!ans.isEmpty())
			{
				RegisteredUser gp = (RegisteredUser)ans.toArray()[0];
				System.out.println("search returns " + gp.getPersonName().toString());
				return gp;
			}
			else
				return null;

		}catch (Exception e) {
			return null;
		}
	}

	protected GenericPerson(String TreeIDString,Name pName, String gender, String religion, String ethnicity, Date dob, Date dop, Contact c)
	{
		treeID = TreeIDString;
		languages = new ArrayList<String>();
		maritalList = new ArrayList<Marriage>();
		resAddresses = new ArrayList<Address>();
		education = new ArrayList<Education>();
		work = new ArrayList<Occupation>();

		languages.clear();
		maritalList.clear();
		resAddresses.clear();
		education.clear();
		work.clear();
		//TODO: code to extract the next ID from the static Database Object.
		generationID = 0;
		PersonName = pName;
		this.gender = gender;
		this.religion = religion;
		this.ethnicity = ethnicity;
		dateOfBirth = dob;
		dateOfPassing = dop;
		contactDetails = c;
		//addedBy = adder;
		this.persist();
	}

	/**
	 * @return the generationID
	 */
	public int getGenerationID() {
		return generationID;
	}
	/**
	 * @param generationID the generationID to set
	 */
	public void setGenerationID(int generationID)
	{
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.generationID = generationID;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the gender
	 */
	public String getGender() {
		return gender;
	}
	/**
	 * @param gender the gender to set
	 */
	public void setGender(String gender) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.gender = gender;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the religion
	 */
	public String getReligion() {
		return religion;
	}
	/**
	 * @param religion the religion to set
	 */
	public void setReligion(String religion) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.religion = religion;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the ethnicity
	 */
	public String getEthnicity() {
		return ethnicity;
	}
	/**
	 * @param ethnicity the ethnicity to set
	 */
	public void setEthnicity(String ethnicity) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.ethnicity = ethnicity;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the dateOfBirth
	 */
	public Date getDateOfBirth() {
		return dateOfBirth;
	}
	/**
	 * @param dateOfBirth the dateOfBirth to set
	 */
	public void setDateOfBirth(Date dateOfBirth) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.dateOfBirth = dateOfBirth;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the contactNumber
	 */
	public Contact getContactNumber() {
		return contactDetails;
	}
	/**
	 * @param contactNumber the contactNumber to set
	 */
	public void setContactDetails(Contact contactDetails) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.contactDetails = contactDetails;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the languages
	 */
	public Collection<String> getLanguages() {
		return languages;
	}
	/**
	 * @param languages the languages to set
	 */
	public void addLanguages(String language) {
		this.languages.add(language);
	}
	/**
	 * @return the spouseList
	 */
	public ArrayList<GenericPerson> getSpouseList() {
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();;

		if(maritalList.isEmpty())
		{
			tmp.clear();
			return tmp;
		}
		else
		{
			for(Marriage m: maritalList)
			{
				if((m.getParticipant1()!= null) && (m.getParticipant1().equals(this)))
				{
						if(m.getParticipant2() != null)
							tmp.add(m.getParticipant2());
				}
				else if((m.getParticipant2() != null) &&(m.getParticipant2().equals(this)))
				{
						if(m.getParticipant1() != null)
							tmp.add(m.getParticipant1());
				}
			}

			return tmp;
		}

	}
	/**
	 * @param spouseList the spouseList to set
	 */
	public void addSpouse(GenericPerson spouse) {
		Marriage m = new Marriage(this, spouse, false, null, null);
		this.addMarriage(m);
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		spouse.addedAsSpouse(this);
		db.pm.currentTransaction().commit();
		spouse.changeTree(this.treeID);
	}
	/**
	 * @return the personName
	 */
	public Name getPersonName() {
		return PersonName;
	}

	/**
	 * @return the maritalList
	 */
	public Collection<Marriage> getMaritalList() {
		return maritalList;
	}
	/**
	 * @param maritalList the maritalList to set
	 */
	public void addMarriage(Marriage m) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		maritalList.add(m);
		db.pm.currentTransaction().commit();
	}

	public void editProfile()
	{

	}

	public void addParent(GenericPerson parent)
	{
		parent.setGenerationID(generationID - 1);
		parent.changeTree(this.treeID);
		if(childOf != null )
		{
			childOf.setParticipant2(parent);
		}
		else
		{
			Marriage mrg = new Marriage(parent, null, false, null, null);
			DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
			db.pm.currentTransaction().begin();
			childOf = mrg;
			db.pm.currentTransaction().commit();
			childOf.addChild(this);
		}

		parent.addedAsParent(this);

	}

	public void addParents(GenericPerson parent1, GenericPerson parent2)
	{
		parent1.setGenerationID(generationID - 1);
		parent1.changeTree(this.treeID);
		parent2.setGenerationID(generationID - 1);
		parent2.changeTree(this.treeID);
		if(childOf != null )
			return;
		else
		{
			childOf = new Marriage(parent1, parent2, false, null, null);
			childOf.addChild(this);
		}

		parent1.addedAsParent(this);
		parent2.addedAsParent(this);

	}

	public void addChild(GenericPerson p, GenericPerson c)
	{		
		Marriage m = null;

		for(Marriage tmp : maritalList )
		{
			if(tmp.getParticipant1().equals(p) || tmp.getParticipant2().equals(p))
			{
				m = tmp;
				break;
			}
		}

		if(m == null)
		{
			Marriage mrg = new Marriage(this, p, false , null , null);
			p.setTreeID(this.treeID);
			addMarriage(mrg);
			for(Marriage tmp : maritalList )
			{
				if((tmp.getParticipant1() != null && tmp.getParticipant1().equals(p)) || (tmp.getParticipant2() != null && tmp.getParticipant2().equals(p)))
				{
					m = tmp;
					break;
				}
			}
		}

		m.addChild(c);
		c.setChildOf(m);
		c.setGenerationID(this.generationID + 1);
		c.addedAschild(this);
		c.changeTree(this.treeID);
	}


	public void addSibling(GenericPerson sib, RegisteredUser creatingUser)
	{
		if(childOf == null)
		{
			if(sib.childOf != null)
				childOf = sib.childOf;
			else
				childOf = new Marriage(creatingUser.createDummyProfile(), creatingUser.createDummyProfile(), false, null, null);	//dummy marriage object
		}

		childOf.addChild(sib);
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		sib.addedAsSibling(this);
		db.pm.currentTransaction().commit();
		sib.changeTree(this.treeID);
	}

	public GenericPerson getMother()
	{
		if(this.childOf == null) return null;
		if (this.childOf.getParticipant1() != null && this.childOf.getParticipant1().gender.equals("female"))
			return this.childOf.getParticipant1();

		else
			return this.childOf.getParticipant2();	
	}


	/*	private ArrayList<GenericPerson> identifyExtremeAncestors(int originalPersonGenerationID, int degreeOfSeparation)
	{
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();
		tmp.clear();
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		Query q = db.pm.newQuery(GenericPerson.class);

		int extremeGenerationID = originalPersonGenerationID - degreeOfSeparation;

		q.setFilter("treeID == \"" + this.treeID + "\"");

		Collection ans = null,ans2 = null;
		try{
			ans = (Collection)q.execute();

			do{
			q.setCandidates(ans);
			q.setFilter("generationID ==" + extremeGenerationID );
			ans2 = (Collection)q.execute();

			extremeGenerationID++;

			if(extremeGenerationID == (originalPersonGenerationID - 1))
				break;

			}while(ans2.isEmpty());


			for(Iterator i = ans.iterator(); i.hasNext() ; )
			{
				GenericPerson gp = (GenericPerson)i.next();
				tmp.add(gp);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			for(GenericPerson gp : tmp)
				System.out.println(gp.toString());

			return tmp;
		}

	}
	 */
	/*	private ArrayList<GenericPerson> identifyExtremeAncestors(int originPersonGenerationID,int degreeOfSeperation, ArrayList<GenericPerson> gplst)
	{
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();
		//identify the extreme ancestor of the person on the father's side
		if( originPersonGenerationID - generationID < degreeOfSeperation)
		{
			if(this.getFather() != null && this.getFather().identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation,gplst) != null)
			{
				for(GenericPerson gp : this.getFather().identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation, gplst))
				{
					tmp.add(gp);
				}
			}
			if(this.getFather() != null && this.getFather().identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation, gplst).isEmpty())
				tmp.add(this.getFather());

			GenericPerson mom = this.getMother();
			if(mom != null && mom.identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation, gplst)!= null)
			{
				for(GenericPerson gp : mom.identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation, gplst))
				{
					tmp.add(gp);
				}
			}
			if(mom != null && mom.identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation, gplst).isEmpty())
			{
				tmp.add(mom);
			}
			return tmp;
		}
		else
		{
			if(gplst == null) gplst = new ArrayList<GenericPerson>();
			gplst.add(this);
			return gplst;
		}

	}
	 */




	public ArrayList<GenericPerson> identifyExtremeAncestors()
	{
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();
		tmp.clear();
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		Query q = db.pm.newQuery(GenericPerson.class);

		q.setFilter("treeID == \"" + this.treeID + "\"");
		q.setOrdering("generationID ascending");
		q.compile();

		Collection ans = null;
		try{
			ans = (Collection)q.execute();

			for(Iterator i = ans.iterator(); i.hasNext() ; )
			{
				GenericPerson gp = (GenericPerson)i.next();
				tmp.add(gp);
			}

		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

		for(GenericPerson gp : tmp)
			System.out.println(gp.toString());

		return tmp;

	}

	public StringBuffer printTree()
	{	
		StringBuffer treeString = new StringBuffer();
		ArrayList<GenericPerson> relatives;
		//identify the extreme ancestor of the person
		ArrayList<GenericPerson> extremeAncestor = identifyExtremeAncestors();


		for(int i = 0 ; i < extremeAncestor.size() ; i++)
		{
			if(i > 0 && extremeAncestor.get(i-1).generationID != extremeAncestor.get(i).generationID)
				System.out.println();

			System.out.print(extremeAncestor.get(i).getPersonName().toString() + "\t");
		}

		relatives = (ArrayList<GenericPerson>) extremeAncestor.clone();

		ArrayList<GenericPerson> listed = new ArrayList<GenericPerson>();

		for(int i = 0 ; i < extremeAncestor.size() ; i++)
		{
			if(i > 0 && extremeAncestor.get(i-1).generationID != extremeAncestor.get(i).generationID)
				treeString.append("||");

			if(!listed.contains(extremeAncestor.get(i)))
			{
				treeString.append("(" + extremeAncestor.get(i).PersonName.identity() + ":" +extremeAncestor.get(i).PersonName.toString() + ")");
				listed.add(extremeAncestor.get(i));

				if(!extremeAncestor.get(i).getChildren().isEmpty())
				{
					treeString.append("- (>[");
					for(GenericPerson ch : extremeAncestor.get(i).getChildren())
						treeString.append(ch.PersonName.identity() + ",");

					treeString.deleteCharAt(treeString.lastIndexOf(","));
					treeString.append("])");
				}
				if(!(extremeAncestor.get(i).getSpouseList().isEmpty()))
				{
					if(extremeAncestor.get(i)!= null && extremeAncestor.get(i).getSpouseList().get(0)!= null && !listed.contains(extremeAncestor.get(i).getSpouseList().get(0)))
					{
						treeString.append(" - (" + extremeAncestor.get(i).getSpouseList().get(0).PersonName.identity() + ":" + extremeAncestor.get(i).getSpouseList().get(0).PersonName.toString() + ")");
						listed.add(extremeAncestor.get(i).getSpouseList().get(0));
					}

				}
			}


		}

		System.out.println();
		System.out.println("the treeString ");
		System.out.println(treeString);

		return treeString;

	}


	/*	public StringBuffer printTree(int originPersonGenerationID,int degreeOfSeperation)
	{	
		StringBuffer treeString = new StringBuffer();
		ArrayList<GenericPerson> relatives;
		//identify the extreme ancestor of the person
		ArrayList<GenericPerson> extremeAncestor = identifyExtremeAncestors(originPersonGenerationID, degreeOfSeperation);

		for(int i = 0; i< extremeAncestor.size() ; i++)
		{	
			for(GenericPerson sp : extremeAncestor.get(i).getSpouseList())
			{
				if(sp != null)
				{
					if(Math.abs(sp.generationID - originPersonGenerationID) < degreeOfSeperation)
						if(!extremeAncestor.contains(sp))
							extremeAncestor.add(sp);
				}
			}
			for(GenericPerson gp : extremeAncestor.get(i).getChildren())
			{
				if(gp != null)
				{
					if(Math.abs(gp.generationID - originPersonGenerationID) < degreeOfSeperation)
						if(!extremeAncestor.contains(gp))
							extremeAncestor.add(gp);
				}
			}

		}

		for(int i = 0 ; i < extremeAncestor.size() ; i++)
		{
			if(i > 0 && extremeAncestor.get(i-1).generationID != extremeAncestor.get(i).generationID)
				System.out.println();

			if(Math.abs(this.generationID - extremeAncestor.get(i).generationID) < degreeOfSeperation)
				System.out.print(extremeAncestor.get(i).getPersonName().toString() + "\t");
		}

		relatives = (ArrayList<GenericPerson>) extremeAncestor.clone();
		for(int i = 0 ; i < extremeAncestor.size() ; i++)
		{
			if(i > 0 && extremeAncestor.get(i-1).generationID != extremeAncestor.get(i).generationID)
				treeString.append("||");

			if(Math.abs(this.generationID - extremeAncestor.get(i).generationID) < degreeOfSeperation)
			{
				treeString.append("(" + extremeAncestor.get(i).PersonName.identity() + ":" +extremeAncestor.get(i).PersonName.toString() + ")");
				if(!extremeAncestor.get(i).getChildren().isEmpty())
				{
					treeString.append("- (>[");
					for(GenericPerson ch : extremeAncestor.get(i).getChildren())
						treeString.append(ch.PersonName.identity() + ",");

					treeString.deleteCharAt(treeString.lastIndexOf(","));
					treeString.append("])");
				}
			}
			if(!extremeAncestor.get(i).getSpouseList().isEmpty())
			{
				treeString.append(" - (" + extremeAncestor.get(i).getSpouseList().get(0).PersonName.identity() + ":" + extremeAncestor.get(i).getSpouseList().get(0).PersonName.toString() + ")");
				extremeAncestor.remove(extremeAncestor.get(i).getSpouseList().get(0));
				extremeAncestor.remove(i);
			}


		}

		System.out.println();
		System.out.println("the treeString ");
		System.out.println(treeString);

		return treeString;

	}
	 */

	public GenericPerson getFather()
	{
		if(this.childOf == null) return null;
		if (this.childOf.getParticipant1() != null && this.childOf.getParticipant1().gender.contains("male"))
			return this.childOf.getParticipant1();

		else
			return this.childOf.getParticipant2();	
	}

	/**
	 * @param childOf the childOf to set
	 */
	public void setChildOf(Marriage childOf) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.childOf = childOf;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the childOf
	 */
	public Marriage getChildOf() {
		return childOf;
	}
	/**
	 * @param dateOfPassing the dateOfPassing to set
	 */
	public void setDateOfPassing(Date dateOfPassing) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.dateOfPassing = dateOfPassing;
		db.pm.currentTransaction().commit();
	}
	/**
	 * @return the dateOfPassing
	 */
	public Date getDateOfPassing() {
		return dateOfPassing;
	}
	/**
	 * @param addedBy the addedBy to set
	 */
	public void setAddedBy(RegisteredUser addedBy) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.addedBy = addedBy;
		db.pm.currentTransaction().commit();
	}

	public Boolean isRegistered()
	{
		if(this.addedBy.equals(this))
			return true;
		else
			return false;
	}

	public Boolean isEditable(RegisteredUser editor)
	{
		if(this.addedBy.equals(editor))
			return true;
		else
			return false;
	}

	/**
	 * @return the addedBy
	 */
	public GenericPerson getAddedBy() {
		return addedBy;
	}


	/**
	 * @return the resAddresses
	 */
	public Collection<Address> getResAddresses() {
		return resAddresses;
	}


	/**
	 * @return the education
	 */
	public Collection<Education> getEducation() {
		return education;
	}


	/**
	 * @return the work
	 */
	public Collection<Occupation> getWork() {
		return work;
	}


	/**
	 * @param personName the personName to set
	 */
	public void setPersonName(Name personName) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		PersonName = personName;
		db.pm.currentTransaction().commit();
	}


	/**
	 * @param resAddresses the resAddresses to set
	 */
	public void addResAddresses(Address resAddress) {
		this.resAddresses.add(resAddress);
	}


	/**
	 * @param education the education to set
	 */
	public void addEducation(Education education) {
		this.education.add(education);
	}


	/**
	 * @param work the work to set
	 */
	public void addWork(Occupation work) {
		this.work.add(work);
	}


	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return (generationID + " -> " + PersonName.toString()); 
	}

	public ArrayList<GenericPerson> getSiblings()
	{
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();
		tmp.clear();

		if(childOf == null)
			return tmp;
		else
		{
			tmp = (ArrayList<GenericPerson>) this.getChildren().clone();
			tmp.remove(this);
			return tmp;
		}
	}

	public ArrayList<GenericPerson> getChildren()
	{
		ArrayList<GenericPerson> tmp = new ArrayList<GenericPerson>();
		tmp.clear();

		for(Marriage m : this.maritalList)
			for(GenericPerson gp : m.getChildList())
				tmp.add(gp);

		return tmp;
	}

	public void addedAschild(GenericPerson parent)
	{
		//Change the generationID of the current profile
		if(this.generationID == (parent.generationID + 1) )
			return;		//The tree is valid and the generationID need not be modified

		this.generationID = parent.generationID + 1;


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(this.getSiblings() != null)
		{
			for(GenericPerson gp : this.getSiblings())
			{
				gp.addedAsSibling(this);
			}
		}


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				if(m.getParticipant1().equals(this))
					m.getParticipant2().addedAsSpouse(this);
				else
					m.getParticipant1().addedAsSpouse(this);
			}
		}


		//Change the generationID of descendant's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				for(GenericPerson gp : m.getChildList())
					gp.addedAschild(this);
			}
		}


		//Change the generationID of ancestor's profile other than the parent
		if(childOf != null)
		{
			childOf.getParticipant1().addedAsParent(this);
			childOf.getParticipant2().addedAsParent(this);
		}

	}

	public void addedAsParent(GenericPerson child)
	{
		//Change the generationID of the current profile
		if(this.generationID == (child.generationID - 1) )
			return;		//The tree is valid and the generationID need not be modified

		this.generationID = child.generationID - 1;


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(this.getSiblings() != null)
		{
			for(GenericPerson gp : this.getSiblings())
			{
				gp.addedAsSibling(this);
			}
		}


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				if(m.getParticipant1().equals(this))
					m.getParticipant2().addedAsSpouse(this);
				else
					m.getParticipant1().addedAsSpouse(this);
			}
		}


		//Change the generationID of descendant's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				for(GenericPerson gp : m.getChildList())
					gp.addedAschild(this);
			}
		}


		//Change the generationID of ancestor's profile other than the parent
		if(childOf != null)
		{
			childOf.getParticipant1().addedAsParent(this);
			childOf.getParticipant2().addedAsParent(this);
		}

	}

	public void addedAsSibling(GenericPerson sibling)
	{
		//Change the generationID of the current profile
		if(this.generationID == sibling.generationID )
			return;		//The tree is valid and the generationID need not be modified

		this.generationID = sibling.generationID;


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(this.getSiblings() != null)
		{
			for(GenericPerson gp : this.getSiblings())
			{
				gp.addedAsSibling(this);
			}
		}


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				if(m.getParticipant1().equals(this))
					m.getParticipant2().addedAsSpouse(this);
				else
					m.getParticipant1().addedAsSpouse(this);
			}
		}


		//Change the generationID of descendant's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				for(GenericPerson gp : m.getChildList())
					gp.addedAschild(this);
			}
		}


		//Change the generationID of ancestor's profile other than the parent
		if(childOf != null)
		{
			childOf.getParticipant1().addedAsParent(this);
			childOf.getParticipant2().addedAsParent(this);
		}

	}

	public void addedAsSpouse(GenericPerson spouse)
	{
		//Change the generationID of the current profile
		if(this.generationID == spouse.generationID )
			return;		//The tree is valid and the generationID need not be modified

		this.generationID = spouse.generationID;


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(this.getSiblings() != null )
		{
			for(GenericPerson gp : this.getSiblings())
			{
				gp.addedAsSibling(this);
			}
		}


		//Change the generationID of sibling's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				if(m.getParticipant1().equals(this))
					m.getParticipant2().addedAsSpouse(this);
				else
					m.getParticipant1().addedAsSpouse(this);
			}
		}


		//Change the generationID of descendant's profile.... May be a good idea to thread??
		if(!maritalList.isEmpty())
		{
			for(Marriage m : maritalList)
			{
				for(GenericPerson gp : m.getChildList())
					gp.addedAschild(this);
			}
		}


		//Change the generationID of ancestor's profile other than the parent
		if(childOf != null)
		{
			childOf.getParticipant1().addedAsParent(this);
			childOf.getParticipant2().addedAsParent(this);
		}

	}


	public void setTreeID(String treeID) {
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.treeID = treeID;
		db.pm.currentTransaction().commit();
	}


	public String getTreeID() {
		return treeID;
	}


	public boolean isSameAs(GenericPerson gp)
	{
		if(!gp.PersonName.getFirstName().equals(this.PersonName.getFirstName()))
			return false;
		if(!gp.PersonName.getLastName().equals(this.PersonName.getLastName()))
			return false;
		if(!gp.contactDetails.getEmail().equals(this.contactDetails.getEmail()))
			return false;

		return true;
	}


	public Contact getContactDetails() {
		return contactDetails;
	}

	public Boolean deleteMe()
	{
		int relationshipCount = 0;
		if(!this.getSpouseList().isEmpty())
			relationshipCount++;
		if(!this.getChildren().isEmpty())
			relationshipCount++;
		if(this.childOf != null)
			relationshipCount++;

		if(relationshipCount > 1)
			return false;

		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();

		if(!this.getSpouseList().isEmpty())
		{
			for(Marriage m : maritalList)
				if(this.isSameAs(m.getParticipant1()))
					m.setParticipant1(null);
				else if(this.isSameAs(m.getParticipant2()))
					m.setParticipant2(null);
		}
		if(!this.getChildren().isEmpty())
		{
			for(GenericPerson gp : this.getChildren())
				if(this.isSameAs(gp.childOf.getParticipant1()))
					gp.childOf.setParticipant1(null);
				else if(this.isSameAs(gp.childOf.getParticipant2()))
					gp.childOf.setParticipant2(null);
		}
		if(this.childOf != null)
		{
			this.childOf.getChildList().remove(this);
		}

		db.pm.deletePersistent(this);
		db.pm.currentTransaction().commit();
		return true;
	}
	public void editProfile(String fName, String mName, String lName, String phNumber)
	{
		DatabaseObject db = DatabaseObjectFactory.getDatabaseObject();
		db.pm.currentTransaction().begin();
		this.PersonName.setFirstName(fName);
		this.PersonName.setMiddleName(mName);
		this.PersonName.setLastName(lName);
		db.pm.currentTransaction().commit();
		this.contactDetails.setPhone(phNumber);
	}
}